package ${domain}.module.wsys.mgr;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.github.pagehelper.util.StringUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.Cache;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import ${domain}.config.CacheConfig;
import ${domain}.frame.auth.LocalData;
import ${domain}.frame.auth.Token;
import ${domain}.frame.base.ErrorType;
import ${domain}.frame.base.SortType;
import ${domain}.frame.utils.IDgenerator;
import ${domain}.frame.utils.MapperUtil;
import ${domain}.frame.utils.Message;
import ${domain}.frame.utils.ValidationUtil;
import ${domain}.module.wsys.ent.Tokens;
import ${domain}.module.wsys.mpr.TokensMapper;
import ${domain}.module.wsys.req.ResLoadRequest;
import ${domain}.module.wsys.req.TokensBuildRequest;
import ${domain}.module.wsys.req.TokensCreateRequest;
import ${domain}.module.wsys.req.TokensDeleteRequest;
import ${domain}.module.wsys.req.TokensFindRequest;
import ${domain}.module.wsys.req.TokensLogoutRequest;
import ${domain}.module.wsys.req.TokensUpdateRequest;
import ${domain}.module.wsys.rsp.ResLoadResponse;
import ${domain}.module.wsys.rsp.TokensBuildResponse;
import ${domain}.module.wsys.rsp.TokensCreateResponse;
import ${domain}.module.wsys.rsp.TokensDeleteResponse;
import ${domain}.module.wsys.rsp.TokensFindResponse;
import ${domain}.module.wsys.rsp.TokensLogoutResponse;
import ${domain}.module.wsys.rsp.TokensUpdateResponse;

/**
 * TOKENS - 通行证
 *
 * @author author
 * @version 0.0.1
 * @since 2017-01-01
 */
@Transactional
@Service
public class TokensManagerImpl implements ${domain}.module.wsys.mgr.TokensManager {

    @Value("${r'${web.url.auth.admin}'}")
    private String admin;
    @Autowired
    private TokensMapper tokensMapper;
    @Autowired
    private UserRoleManager userRoleManager;
    @Autowired
    private ResManager resManager;

    /**
     * 插入
     *
     * @param request 请求对象
     * @param token   令牌
     * @return 响应
     */
    public TokensCreateResponse create(TokensCreateRequest request, Token token) {
        TokensCreateResponse response = new TokensCreateResponse();

        ValidationUtil.validate(request, response);
        if (response.hasError()) {
            return response;
        }

        {// 检查是否有其他登录信息，是否多端登录，并注销
            TokensFindRequest tokensFindRequest = new TokensFindRequest();
            tokensFindRequest.setUserId(request.getUserId());
            tokensFindRequest.setUserName(request.getUserName());
            tokensFindRequest.setValid(true);
            tokensFindRequest.setTerminal(request.getTerminal());
            tokensFindRequest.setPageSize(0);
            tokensFindRequest.setSortKey("CREATE_TIME");
            tokensFindRequest.setSortType(SortType.ASC);
            TokensFindResponse tokensFindResponse = this.find(tokensFindRequest, token);
            if (tokensFindResponse.hasError()) {
                response.addErrors(tokensFindResponse.getErrors());
                return response;
            }

            for (Tokens tokens : tokensFindResponse.getResult()) {
                TokensLogoutRequest tokensLogoutRequest = new TokensLogoutRequest();
                tokensLogoutRequest.setToken(tokens.getToken());
                // 为何不是直接使用this？如果直接this调用无法被Spring代理，注解即失效
                TokensManager tokensManager = LocalData.getBean(TokensManager.class);
                TokensLogoutResponse tokensLogoutResponse = tokensManager.logout(tokensLogoutRequest, token);
                if (tokensLogoutResponse.hasError()) {
                    response.addErrors(tokensLogoutResponse.getErrors());
                    return response;
                }
            }
        }

        long id = IDgenerator.nextId();
        Tokens entity = MapperUtil.map(request, Tokens.class);
        if (StringUtil.isEmpty(entity.getUserAlias())){
            entity.setUserAlias(entity.getUserName());
        }
        entity.setId(id);

        long result = tokensMapper.insert(entity, token);
        if (1L != result) {
            response.addError(ErrorType.BUSINESS_ERROR, Message.CREATE_FAILURE);
            return response;
        }
        response.setId(id);

        return response;
    }

    /**
     * 逻辑删除
     *
     * @param request 请求对象
     * @param token   令牌
     * @return 响应
     */
    public TokensDeleteResponse delete(TokensDeleteRequest request, Token token) {
        TokensDeleteResponse response = new TokensDeleteResponse();

        if (request.getId() != null) {
            Tokens tokens = tokensMapper.getById(request.getId(), token);
            long result = tokensMapper.delete(request.getId(), token);
            if (1L != result) {
                response.addError(ErrorType.BUSINESS_ERROR, Message.DELETE_FAILURE);
                return response;
            }
            response.setResult(result);
            Cache cache = CacheConfig.getCache(CacheConfig.TOKEN_CACHE);
            cache.evict(tokens.getToken());
        } else if (StringUtil.isNotEmpty(request.getToken())) {
            TokensFindRequest tokensFindRequest = new TokensFindRequest();
            tokensFindRequest.setValid(true);
            tokensFindRequest.setToken(request.getToken());
            tokensFindRequest.setPageSize(0);
            TokensFindResponse tokensFindResponse = this.find(tokensFindRequest, token);
            for (Tokens tokens : tokensFindResponse.getResult()) {
                long result = tokensMapper.delete(tokens.getId(), token);
                if (1L != result) {
                    response.addError(ErrorType.BUSINESS_ERROR, Message.DELETE_FAILURE);
                    return response;
                }
                Cache cache = CacheConfig.getCache(CacheConfig.TOKEN_CACHE);
                cache.evict(tokens.getToken());
            }
            response.setResult(tokensFindResponse.getTotalCount());
        } else {
            response.addError(ErrorType.BUSINESS_ERROR, "登录凭证标识不存在!");
        }

        return response;
    }

    /**
     * 更新
     *
     * @param request 请求对象
     * @param token   令牌
     * @return 响应
     */
    @CacheEvict(value = CacheConfig.TOKEN_CACHE, key = "#request.token", condition = "!#result.hasError()")
    public TokensUpdateResponse update(TokensUpdateRequest request, Token token) {
        TokensUpdateResponse response = new TokensUpdateResponse();

        ValidationUtil.validate(request, response);
        if (response.hasError()) {
            return response;
        }

        Tokens entity = tokensMapper.getById(request.getId(), token);
        if (entity == null) {
            response.addError(ErrorType.BUSINESS_ERROR, Message.GET_FAILURE);
            return response;
        }

        MapperUtil.map(request, entity);
        if (StringUtil.isEmpty(entity.getUserAlias())){
            entity.setUserAlias(entity.getUserName());
        }
        long result = tokensMapper.update(entity, token);
        if (1L != result) {
            response.addError(ErrorType.BUSINESS_ERROR, Message.UPDATE_FAILURE);
            return response;
        }
        response.setResult(result);

        return response;
    }

    /**
     * 查询
     *
     * @param request 请求对象
     * @param token   令牌
     * @return 响应
     */
    @Transactional(readOnly = true)
    public TokensFindResponse find(TokensFindRequest request, Token token) {
        TokensFindResponse response = new TokensFindResponse();

        ValidationUtil.validate(request, response);
        if (response.hasError()) {
            return response;
        }

        if (request.getPageSize() != 0) {
            PageHelper.startPage(request.getPageNumber(), request.getPageSize());
        }
        if (StringUtil.isNotEmpty(request.getSortKey())) {
            PageHelper.orderBy(request.getSortKey() + " " + request.getSortType());
        }
        PageInfo<Tokens> pageInfo = new PageInfo<>(tokensMapper.find(request, token));

        response.setResult(pageInfo.getList());
        response.setTotalCount(pageInfo.getTotal());

        return response;
    }

    /**
     * 构建Token
     *
     * @param request 请求对象
     * @param token   令牌
     * @return
     */
    @Override
    @Cacheable(value = CacheConfig.TOKEN_CACHE, key = "#request.token", unless = "#result.hasError()")
    public TokensBuildResponse build(TokensBuildRequest request, Token token) {
        TokensBuildResponse response = new TokensBuildResponse();

        ValidationUtil.validate(request, response);
        if (response.hasError()) {
            return response;
        }

        TokensFindRequest tokensFindRequest = MapperUtil.map(request, TokensFindRequest.class);
        tokensFindRequest.setValid(true);
        TokensFindResponse tokensFindResponse = this.find(tokensFindRequest, token);
        if (tokensFindResponse.hasError()) {
            response.addErrors(tokensFindResponse.getErrors());
            return response;
        }

        if (tokensFindResponse.getResult().size() == 0) {
            response.addError(ErrorType.BUSINESS_ERROR, "令牌无效或不存在");
            return response;
        } else if (tokensFindResponse.getResult().size() > 1) {
            response.addError(ErrorType.BUSINESS_ERROR, "令牌异常");
            return response;
        } else {
            Tokens tokens = tokensFindResponse.getResult().get(0);
            Token newToken = new Token();
            newToken.setId(tokens.getId());
            newToken.setToken(tokens.getToken());
            newToken.setUserId(tokens.getUserId());
            newToken.setUserName(tokens.getUserName());
            newToken.setUserAlias(tokens.getUserAlias());
            if (tokens.getUserName().equals(admin)) {//超级管理员
                newToken.putRes(".*");
            } else { // 管理员或用户
                // 加载用户的资源
                ResLoadRequest resLoadRequest = new ResLoadRequest();
                resLoadRequest.setPageSize(0);
                resLoadRequest.setUserId(tokens.getUserId());
                ResLoadResponse resFindResponse = resManager.load(resLoadRequest, token);
                if (resFindResponse.hasError()) {
                    response.addErrors(resFindResponse.getErrors());
                    return response;
                }
                newToken.putRes(resFindResponse.getResult());
            }

            response.setToken(newToken);
        }

        return response;
    }

    @Override
    @CacheEvict(value = CacheConfig.TOKEN_CACHE, key = "#request.token", condition = "!#result.hasError()")
    public TokensLogoutResponse logout(TokensLogoutRequest request, Token token) {
        TokensLogoutResponse response = new TokensLogoutResponse();

        ValidationUtil.validate(request, response);
        if (response.hasError()) {
            return response;
        }

        if (request.getToken().equals(token.getToken())) {
            response.addError(ErrorType.BUSINESS_ERROR, "无法注销当前登录用户!");
            return response;
        }

        TokensFindRequest tokensFindRequest = MapperUtil.map(request, TokensFindRequest.class);
        tokensFindRequest.setValid(true);
        TokensFindResponse tokensFindResponse = this.find(tokensFindRequest, token);
        if (tokensFindResponse.hasError()) {
            response.addErrors(tokensFindResponse.getErrors());
            return response;
        }

        for (Tokens tokens : tokensFindResponse.getResult()) {
            tokens.setValid(false);
            long result = tokensMapper.update(tokens, token);
            if (1L != result) {
                response.addError(ErrorType.BUSINESS_ERROR, Message.UPDATE_FAILURE);
                return response;
            }
        }

        return response;
    }
}
